package com.security.control.browser.session;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.security.control.core.support.SimpleResponseEntity;
import com.security.control.core.properties.SecurityProperties;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author imoot@gamil.com
 * @date 2019/1/9 0009 15:14
 * ----抽象的session失效处理器
 */
public class AbstractSessionStrategy {

    private final Logger log = LoggerFactory.getLogger(AbstractSessionStrategy.class);

    private String destinationUrl;//跳转的url

    private SecurityProperties securityProperties;

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();//重定向策略

    private boolean createNewSession = true;//跳转前是否创建新的session

    private ObjectMapper objectMapper = new ObjectMapper();

    /**
     * @param securityProperties
     * 构造函数，传入系统配置来并做session失效地址的校验
     */
    public AbstractSessionStrategy(SecurityProperties securityProperties) {
        String invalidSessionUrl = securityProperties.getSessionProperties().getInvalidSessionUrl();
        Assert.isTrue(UrlUtils.isValidRedirectUrl(invalidSessionUrl), "url must start with '/' or 'http(s)'");//url必须以"/"或者"http(s)"开头
        Assert.isTrue(StringUtils.endsWithIgnoreCase(invalidSessionUrl, ".html"), "url must end with '.html'");//url必须以".html"结尾
        this.destinationUrl = invalidSessionUrl;
        this.securityProperties = securityProperties;
    }

    /**
     * @param request
     * @param response
     * @throws IOException
     * 当session失效时，做出相应判断
     */
    protected void onSessionInvalid(HttpServletRequest request, HttpServletResponse response) throws IOException {
        log.info("session 失效");

        if (createNewSession) {
            request.getSession();
        }

        String sourceUrl = request.getRequestURI();
        String targetUrl;

        //判断是html请求，跳转到session失效的请求页面；如果不是html请求，则返回提示session失效的字符串
        if (StringUtils.endsWithIgnoreCase(sourceUrl, ".html")) {
            if (StringUtils.equals(sourceUrl, securityProperties.getBrowserProperties().getSignInUrl()) || StringUtils.equals(sourceUrl, securityProperties.getBrowserProperties().getLogoutUrl())) {
                targetUrl = sourceUrl;
            } else {
                targetUrl = destinationUrl;
            }
            log.info("跳转到：" + targetUrl);
            redirectStrategy.sendRedirect(request, response, targetUrl);
        } else {
            Object result = buildResponseContent(request);
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write(objectMapper.writeValueAsString(result));
        }
    }

    /**
     * @param request
     * 创建响应内容
     */
    protected Object buildResponseContent(HttpServletRequest request) {
        String message = "session已失效";
        if (isConcurrency()) {
            message = message + "，有可能是并发登录导致的";
        }
        return new SimpleResponseEntity(message);
    }

    /**
     * session失效是否是并发导致的
     */
    protected boolean isConcurrency() {
        return false;
    }

    public void setCreateNewSession(boolean createNewSession) {
        this.createNewSession = createNewSession;
    }
}
